#pragma once
#include "sem.hpp"
#include "mutex.hpp"
#include <vector>
using namespace SemModule;
using namespace MutexModule;
static int gsize = 5; // for debug

namespace RingQueueModule
{
    template <typename T>
    class ringqueue
    {
    public:
        ringqueue(int size = gsize)
            : _rq(size), _cap(size), _sem_blank(size), _sem_data(0), _p_index(0), _c_index(0)
        {
        }
        void Put(const T data)
        {
            /* 先申请到信号量，再上锁访问临界资源 */
            _sem_blank.P();
            {
                /* 上锁 */
                LockGuard lcokguard(_pmutex);
                /* 放入数据 */
                _rq[_p_index] = data;
                ++_p_index;
                _p_index %= _cap;
            }
             /* 发送信号量 */
             _sem_data.V(); 
        }

        void Get(T *out)
        {
            /* 先申请信号量，再上锁访问临界资源 */
            _sem_data.P();
            {
                /* 上锁 */
                LockGuard lcokguard(_cmutex);
                /* 取出数据 */
                *out = _rq[_c_index];
                ++_c_index;
                _c_index %= _cap;
            }
            /* 发送信号量 */
            _sem_blank.V();
        }

        ~ringqueue() {}

    private:
        /* 循环队列 */
        std::vector<T> _rq;
        int _cap; /* 表示容量 */
        /* 两个信号量 */
        Sem _sem_blank; /* 生产者信号量 */
        Sem _sem_data;  /* 消费者信号量 */
        int _p_index;   /* 表示生产者下标 */
        int _c_index;   /* 表示消费者下标 */
        /* 锁 --> 为了解决多生产多消费访问临界资源的问题 */
        Mutex _pmutex; /* 生产者锁 */
        Mutex _cmutex; /* 消费者锁 */
    };
}
